#include "main.h"
#include "project.h"

#include <stdio.h>
#include <string.h>

void ProjectInit(ProjectTypeDef *project) {
    ProjectInitSensorParam(project);

    project->equipId = 1866437208922775554;
    project->run = true;
    project->autoControl = true;
    project->controlBackCount = 0;
    project->dht11ErrCount = 0;
    project->dht11NormalOper = true;
    project->lightErrCount = 0;
    project->lightNormalOper = true;

    project->byj28State = false;
    project->esp01sState = true;
}

void ProjectInitSensorParam(ProjectTypeDef *project) {
    project->dht11Suc = false;
    project->dht11HumiInt = 0;
    project->dht11HumiDec = 0;
    project->dht11TempInt = 0;
    project->dht11TempDec = 0;
    project->dht11Check = 0;
    project->dht11Humidity = 0.0f;
    project->dht11Temperature = 0.0f;

    project->lightSuc = false;
    project->lightPercent = 0.0f;
    project->lightAdcVal = 0;
}

int ProjectDataAssemble(const ProjectTypeDef *project, char *outputBuf, const uint32_t size) {
    const int len = snprintf(outputBuf, size,
                             "{"
                             "\"equipId\":%llu,"
                             "\"autoControl\":%d,"
                             "\"controlBackCount\":%d,"
                             "\"dht11ErrCount\":%u,"
                             "\"dht11NormalOper\":%d,"
                             "\"lightErrCount\":%u,"
                             "\"lightNormalOper\":%d,"
                             "\"dht11Suc\":%d,"
                             "\"dht11HumiInt\":%u,"
                             "\"dht11HumiDec\":%u,"
                             "\"dht11TempInt\":%u,"
                             "\"dht11TempDec\":%u,"
                             "\"dht11Check\":%u,"
                             "\"dht11Humidity\":%.1f,"
                             "\"dht11Temperature\":%.1f,"
                             "\"lightSuc\":%d,"
                             "\"lightPercent\":%.1f,"
                             "\"lightAdcVal\":%u,"
                             "\"byj28State\":%d,"
                             "\"esp01sState\":%d"
                             "}\r\n",
                             project->equipId,
                             project->autoControl ? 1 : 0, // 改为1/0
                             project->controlBackCount,
                             project->dht11ErrCount,
                             project->dht11NormalOper ? 1 : 0, // 改为1/0
                             project->lightErrCount,
                             project->lightNormalOper ? 1 : 0, // 改为1/0
                             project->dht11Suc ? 1 : 0, // 改为1/0
                             project->dht11HumiInt,
                             project->dht11HumiDec,
                             project->dht11TempInt,
                             project->dht11TempDec,
                             project->dht11Check,
                             project->dht11Humidity,
                             project->dht11Temperature,
                             project->lightSuc ? 1 : 0, // 改为1/0
                             project->lightPercent,
                             project->lightAdcVal,
                             project->byj28State ? 1 : 0, // 改为1/0
                             project->esp01sState ? 1 : 0 // 改为1/0
    );
    if (len < 0) {
        strncpy(outputBuf, "{\"error\":\"format_error\"}", size);
        return -1;
    }
    if ((unsigned) len >= size) {
        strncpy(outputBuf, "{\"error\":\"buffer_overflow\"}", size);
        return -1;
    }
    return len;
}

bool ProjectAutoControl(ProjectTypeDef *project) {
    if (project->autoControl)
        return true;
    if (project->controlBackCount++ > COMMON_CONTROL_BACK_COUNT) {
        project->autoControl = true;
        project->controlBackCount = 0;
    ProjectLedTip(3);
    }
    return project->autoControl;
}

void ProjectManualControl(ProjectTypeDef *project) {
    project->autoControl = false;
    project->controlBackCount = 0;
    ProjectLedTip(5);
}

void ProjectLedTip(int c) {
    for (int i = 0; i < c; i++) {
        HAL_GPIO_WritePin(Inner_led_GPIO_Port, Inner_led_Pin, GPIO_PIN_SET);
        HAL_Delay(100);
        HAL_GPIO_WritePin(Inner_led_GPIO_Port, Inner_led_Pin, GPIO_PIN_RESET);
        HAL_Delay(100);
    }
}


void Hardware_run(ProjectTypeDef *project) {
    project->run = true;
    HAL_GPIO_WritePin(Inner_led_GPIO_Port, Inner_led_Pin, GPIO_PIN_RESET);
    ProjectInit(project);
}

void Hardware_stop(ProjectTypeDef *project) {
    project->run = false;
    Hardware_motorClose(project);
    HAL_GPIO_WritePin(Inner_led_GPIO_Port, Inner_led_Pin, GPIO_PIN_SET);
}

void Hardware_motorOpen(ProjectTypeDef *project) {
    if (!project->byj28State) {
        project->byj28State = true;
        Hardware_motorRotateCWRound(1);
    }
}

void Hardware_motorClose(ProjectTypeDef *project) {
    if (project->byj28State) {
        project->byj28State = false;
        Hardware_motorRotateCCWRound(1);
    }
}

/**
 * MOTOR START ********************************
 */


uint16_t motorPins[4] = {
    Hardware_motor01_Pin,
    Hardware_motor02_Pin,
    Hardware_motor03_Pin,
    Hardware_motor04_Pin
};

static int motorPinSize = sizeof(motorPins) / sizeof(motorPins[0]);
static int motorRound = 1 << 9; // 转一圈需要通电次数

void Hardware_motorRotateCW(void) {
    for (int i = 0; i < motorPinSize; i++) {
        HAL_GPIO_WritePin(Hardware_motor_GPIO_Port, motorPins[i], GPIO_PIN_SET);
        HAL_Delay(5);
        HAL_GPIO_WritePin(Hardware_motor_GPIO_Port, motorPins[i], GPIO_PIN_RESET);
        HAL_Delay(5);
    }
}

void Hardware_motorRotateCCW(void) {
    for (int i = motorPinSize - 1; i > 0; i--) {
        HAL_GPIO_WritePin(Hardware_motor_GPIO_Port, motorPins[i], GPIO_PIN_SET);
        HAL_Delay(5);
        HAL_GPIO_WritePin(Hardware_motor_GPIO_Port, motorPins[i], GPIO_PIN_RESET);
        HAL_Delay(5);
    }
}

void Hardware_motorRotateCWRound(const int round) {
    for (int i = 0; i < round; i++)
        for (int j = 0; j < motorRound; ++j)
            Hardware_motorRotateCW();
}

void Hardware_motorRotateCCWRound(const int round) {
    for (int i = 0; i < round; i++)
        for (int j = 0; j < motorRound; ++j)
            Hardware_motorRotateCCW();
}

/**
 * ******************************** MOTOR END
 */

/**
 * DHT11 START ********************************
 */


void Hardware_dht11Start(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = Hardware_dht11_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(Hardware_dht11_GPIO_Port, &GPIO_InitStruct);

    HAL_GPIO_WritePin(Hardware_dht11_GPIO_Port, Hardware_dht11_Pin, GPIO_PIN_RESET);
    HAL_Delay(30);
    HAL_GPIO_WritePin(Hardware_dht11_GPIO_Port, Hardware_dht11_Pin, GPIO_PIN_SET);
    HAL_DelayUs(40);

    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(Hardware_dht11_GPIO_Port, &GPIO_InitStruct);
}

uint8_t Hardware_dht11CheckResponse(void) {
    uint32_t timeout = 10000;
    while (HAL_GPIO_ReadPin(Hardware_dht11_GPIO_Port, Hardware_dht11_Pin) && timeout--) {
    }
    if (timeout == 0)return 0;
    timeout = 10000;
    while (!HAL_GPIO_ReadPin(Hardware_dht11_GPIO_Port, Hardware_dht11_Pin) && timeout--) {
    }
    if (timeout == 0)return 0;
    return 1;
}

uint8_t Hardware_dht11Read(void) {
    uint32_t timeout = 10000;
    while (HAL_GPIO_ReadPin(Hardware_dht11_GPIO_Port, Hardware_dht11_Pin) == GPIO_PIN_RESET && timeout--) {
    }
    if (timeout == 0) return 0;
    uint32_t time = 0;
    while (HAL_GPIO_ReadPin(Hardware_dht11_GPIO_Port, Hardware_dht11_Pin) == GPIO_PIN_SET) {
        time++;
        HAL_DelayUs(2);
        if (time > 100) break;
    }
    return time > 40 ? 1 : 0;
}

bool Hardware_dht11GetData(ProjectTypeDef *project) {
    Hardware_dht11Start();
    if (!Hardware_dht11CheckResponse())
        return false;
    uint8_t dht11_data[5] = {0};
    for (int i = 0; i < 5; i++) {
        dht11_data[i] = 0;
        for (int j = 0; j < 8; j++) {
            dht11_data[i] <<= 1;
            dht11_data[i] |= Hardware_dht11Read();
        }
    }
    if (dht11_data[0] + dht11_data[1] + dht11_data[2] + dht11_data[3] == dht11_data[4]) {
        project->dht11Suc = true;
        project->dht11HumiInt = dht11_data[0];
        project->dht11HumiDec = dht11_data[1];
        project->dht11TempInt = dht11_data[2];
        project->dht11TempDec = dht11_data[3];
        project->dht11Check = dht11_data[4];
        project->dht11Humidity = (float) project->dht11HumiInt + (float) project->dht11HumiDec;
        project->dht11Temperature = (float) project->dht11TempInt + (float) project->dht11TempDec;
        return true;
    }
    return false;
}

/**
 * ******************************** DHT11 END
 */

/**
 * LIGHT START ********************************
 */

static ADC_HandleTypeDef *lightAdc = NULL;

void Hardware_lightInit(ADC_HandleTypeDef *hadc) {
    lightAdc = hadc;
    ADC_ChannelConfTypeDef sConfig = {0};
    sConfig.Channel = ADC_CHANNEL_8;
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_71CYCLES_5;
    if (HAL_ADC_ConfigChannel(lightAdc, &sConfig) != HAL_OK) {
        Error_Handler();
    }
}

uint16_t Hardware_lightReadOriginal(void) {
    if (lightAdc == NULL) return 0;
    HAL_ADC_Start(lightAdc);
    HAL_ADC_PollForConversion(lightAdc, HAL_MAX_DELAY);
    const uint16_t adcValue = HAL_ADC_GetValue(lightAdc);
    HAL_ADC_Stop(lightAdc);
    return adcValue;
}

float Hardware_lightReadVoltage(void) {
    const uint16_t adcValue = Hardware_lightReadOriginal();
    return adcValue * COMMON_LIGHT_VOL / 4095.0f; // 12位ADC, 3.3V参考电压
}


float Hardware_lightReadPercent(ProjectTypeDef *project) {
    const uint16_t adcValue = Hardware_lightReadOriginal();
    float percent = 100.0f - (adcValue - COMMON_LIGHT_LIGHT) * 100.0f / (COMMON_LIGHT_DARK - COMMON_LIGHT_LIGHT);
    percent = percent < 0
                  ? 0
                  : percent > 100
                        ? 100
                        : percent;
    project->lightSuc = true;
    project->lightPercent = percent;
    project->lightAdcVal = adcValue;

    return percent;
}


/**
 * ******************************** LIGHT END
 */


/**
 * ESP01S START ********************************
 */

extern UART_HandleTypeDef huart1;
extern UART_HandleTypeDef huart2;

char esp01s_buffer[ESP01S_BUFFER_SIZE];

void Hardware_esp01sInit(void) {
    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin = ESP01S_RST_Pin;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(ESP01S_RST_GPIO_Port, &GPIO_InitStruct);
    GPIO_InitStruct.Pin = ESP01S_EN_Pin;
    HAL_GPIO_Init(ESP01S_EN_GPIO_Port, &GPIO_InitStruct);
    HAL_GPIO_WritePin(ESP01S_EN_GPIO_Port, ESP01S_EN_Pin, GPIO_PIN_SET);
    Hardware_esp01sReset();
    HAL_Delay(2000);
}

void Hardware_esp01sReset(void) {
    HAL_GPIO_WritePin(ESP01S_RST_GPIO_Port, ESP01S_RST_Pin, GPIO_PIN_RESET);
    HAL_Delay(100);
    HAL_GPIO_WritePin(ESP01S_RST_GPIO_Port, ESP01S_RST_Pin, GPIO_PIN_SET);
    HAL_Delay(1000);
}

bool Hardware_esp01sTest(void) {
    HAL_UART_Transmit(&huart2, "AT\r\n", 4, HAL_MAX_DELAY);
    return Hardware_esp01sWaitResponse("OK", 1000);
}

bool Hardware_esp01sConnectWiFi(void) {
    HAL_UART_Transmit(&huart2, "AT+CWMODE=1\r\n", 13, HAL_MAX_DELAY);
    if (!Hardware_esp01sWaitResponse("OK", 2000)) return false;
    char cmd[128];
    snprintf(cmd, sizeof(cmd), "AT+CWJAP=\"%s\",\"%s\"\r\n", WIFI_SSID, WIFI_PASSWORD);
    HAL_UART_Transmit(&huart2, cmd, strlen(cmd), HAL_MAX_DELAY);
    return Hardware_esp01sWaitResponse("OK", 10000);
}

bool Hardware_esp01sSendHttpGet(const char *path, const char *data) {
    char cmd[128];
    snprintf(cmd, sizeof(cmd), "AT+CIPSTART=\"TCP\",\"%s\",%s\r\n", SERVER_IP, SERVER_PORT);
    HAL_UART_Transmit(&huart2, cmd, strlen(cmd), HAL_MAX_DELAY);
    if (!Hardware_esp01sWaitResponse("OK", 5000)) return false;
    char httpRequest[1024];
    if (data && data[0] != '\0') {
        snprintf(httpRequest, sizeof(httpRequest), "GET %s?%s HTTP/1.1\r\nHost: %s:%s\r\nConnection: close\r\n\r\n",
                 path, data, SERVER_IP, SERVER_PORT);
    } else {
        snprintf(httpRequest, sizeof(httpRequest), "GET %s HTTP/1.1\r\nHost: %s:%s\r\nConnection: close\r\n\r\n", path,
                 SERVER_IP, SERVER_PORT);
    }
    snprintf(cmd, sizeof(cmd), "AT+CIPSEND=%d\r\n", strlen(httpRequest));
    HAL_UART_Transmit(&huart2, cmd, strlen(cmd), HAL_MAX_DELAY);
    if (!Hardware_esp01sWaitResponse(">", 1000)) return false;
    HAL_UART_Transmit(&huart2, httpRequest, strlen(httpRequest), HAL_MAX_DELAY);
    volatile bool success = Hardware_esp01sWaitResponse("SEND OK", 5000);
    HAL_UART_Transmit(&huart2, "AT+CIPCLOSE\r\n", 12, HAL_MAX_DELAY);
    Hardware_esp01sWaitResponse("OK", 1000);
    return success;
}

bool Hardware_esp01sSendHttpPost(const char *path, const char *json_data) {
    char cmd[128];
    snprintf(cmd, sizeof(cmd), "AT+CIPSTART=\"TCP\",\"%s\",%s\r\n", SERVER_IP, SERVER_PORT);
    HAL_UART_Transmit(&huart2, cmd, strlen(cmd), HAL_MAX_DELAY);
    if (!Hardware_esp01sWaitResponse("OK", 5000)) return false;
    char httpRequest[1024];
    if (json_data) {
        snprintf(httpRequest, sizeof(httpRequest),
                 "POST %s HTTP/1.1\r\nHost: %s:%s\r\nContent-Type: application/json\r\nContent-Length: %d\r\nConnection: close\r\n\r\n%s",
                 path, SERVER_IP, SERVER_PORT, strlen(json_data), json_data);
    } else {
        snprintf(httpRequest, sizeof(httpRequest),
                 "POST %s HTTP/1.1\r\nHost: %s:%s\r\nContent-Type: application/json\r\nContent-Length: 0\r\nConnection: close\r\n\r\n",
                 path, SERVER_IP, SERVER_PORT);
    }
    snprintf(cmd, sizeof(cmd), "AT+CIPSEND=%d\r\n", strlen(httpRequest));
    HAL_UART_Transmit(&huart2, cmd, strlen(cmd), HAL_MAX_DELAY);
    if (!Hardware_esp01sWaitResponse(">", 1000)) return false;
    HAL_UART_Transmit(&huart2, httpRequest, strlen(httpRequest), HAL_MAX_DELAY);
    volatile bool success = Hardware_esp01sWaitResponse("SEND OK", 5000);
    HAL_UART_Transmit(&huart2, "AT+CIPCLOSE\r\n", 12, HAL_MAX_DELAY);
    Hardware_esp01sWaitResponse("OK", 1000);
    return success;
}

bool Hardware_esp01sWaitResponse(const char *expected, const uint32_t timeout) {
    const uint32_t start = HAL_GetTick();
    uint32_t index = 0;
    memset(esp01s_buffer, 0, ESP01S_BUFFER_SIZE);
    while (HAL_GetTick() - start < timeout) {
        uint8_t byte;
        if (HAL_UART_Receive(&huart2, &byte, 1, 10) == HAL_OK) {
            esp01s_buffer[index++] = byte;
            if (strstr(esp01s_buffer, expected) != NULL) return true;
            if (index >= ESP01S_BUFFER_SIZE - 1) index = 0;
        }
    }
    return false;
}

/**
 * ******************************** ESP01S END
 */
